<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Seata | Hexo</title>
  <meta name="keywords" content=" Spring Cloud Alibaba ">
  <meta name="description" content="Seata | Hexo">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<meta name="description" content="如何解决消息过期失效问题RabbtiMQ 是可以设置过期时间的，也就是 TTL。如果消息在 queue 中积压超过一定的时间就会被 RabbitMQ 给清理掉，这个数据就没了。这就是说数据不会大量积压在 mq 里，而是大量的数据会直接搞丢。解决方法就是采用批量重导。 批量重导，也就是后期的一种手动补偿手段。当高峰期过去之后将丢失的那部分数据，写个临时程序查出来，重新放到MQ里，把白天的数据补回来。">
<meta property="og:type" content="article">
<meta property="og:title" content="Rabbit MQ（面试）">
<meta property="og:url" content="https://xiaomaer-sss.gitee.io/xiaomaer-sss/2023/02/03/Rabbit%20MQ%EF%BC%88%E9%9D%A2%E8%AF%95%EF%BC%89/index.html">
<meta property="og:site_name" content="Hexo">
<meta property="og:description" content="如何解决消息过期失效问题RabbtiMQ 是可以设置过期时间的，也就是 TTL。如果消息在 queue 中积压超过一定的时间就会被 RabbitMQ 给清理掉，这个数据就没了。这就是说数据不会大量积压在 mq 里，而是大量的数据会直接搞丢。解决方法就是采用批量重导。 批量重导，也就是后期的一种手动补偿手段。当高峰期过去之后将丢失的那部分数据，写个临时程序查出来，重新放到MQ里，把白天的数据补回来。">
<meta property="og:locale" content="en_US">
<meta property="article:published_time" content="2023-02-03T13:04:21.063Z">
<meta property="article:modified_time" content="2023-02-04T03:42:41.460Z">
<meta property="article:author" content="kiwi">
<meta property="article:tag" content="队列">
<meta property="article:tag" content="异步">
<meta name="twitter:card" content="summary">


<link rel="icon" href="/img/avatar.jpg">

<link href="/css/style.css?v=1.1.0" rel="stylesheet">

<link href="/css/hl_theme/atom-light.css?v=1.1.0" rel="stylesheet">

<link href="//cdn.jsdelivr.net/npm/animate.css@4.1.0/animate.min.css" rel="stylesheet">

<script src="//cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.min.js"></script>
<script src="/js/titleTip.js?v=1.1.0" ></script>

<script src="//cdn.jsdelivr.net/npm/highlightjs@9.16.2/highlight.pack.min.js"></script>
<script>
    hljs.initHighlightingOnLoad();
</script>

<script src="//cdn.jsdelivr.net/npm/nprogress@0.2.0/nprogress.min.js"></script>



<script src="//cdn.jsdelivr.net/npm/jquery.cookie@1.4.1/jquery.cookie.min.js" ></script>

<script src="/js/iconfont.js?v=1.1.0" ></script>

<meta name="generator" content="Hexo 5.4.2"></head>
<div style="display: none">
  <input class="theme_disqus_on" value="false">
  <input class="theme_preload_comment" value="">
  <input class="theme_blog_path" value="">
  <input id="theme_shortcut" value="true" />
  <input id="theme_highlight_on" value="true" />
  <input id="theme_code_copy" value="true" />
</div>



<body>
<aside class="nav">
    <div class="nav-left">
        <a href="/"
   class="avatar_target">
    <img class="avatar"
         src="/img/avatar.jpg"/>
</a>
<div class="author">
    <span>kiwi</span>
</div>

<div class="icon">
    
        
    
        
    
        
    
        
    
        
    
        
    
        
    
        
    
        
    
        
    
        
            <a title="csdn"
               href="https://blog.csdn.net/weixin_45340300?type=blog"
               target="_blank">
                
                    <svg class="iconfont-svg" aria-hidden="true">
                        <use xlink:href="#icon-csdn"></use>
                    </svg>
                
            </a>
        
    
        
    
        
    
        
            <a title="email"
               href="mailto:jackma.h@foxmail.com"
               target="_blank">
                
                    <svg class="iconfont-svg" aria-hidden="true">
                        <use xlink:href="#icon-email"></use>
                    </svg>
                
            </a>
        
    
        
            <a title="qq"
               href="http://wpa.qq.com/msgrd?v=3&uin=761791958&site=qq&menu=yes"
               target="_blank">
                
                    <svg class="iconfont-svg" aria-hidden="true">
                        <use xlink:href="#icon-qq"></use>
                    </svg>
                
            </a>
        
    
        
    
        
    
</div>




<ul>
    <li>
        <div class="all active" data-rel="All">All
            
                <small>(34)</small>
            
        </div>
    </li>
    
        
            
                <li>
                    <div data-rel="开发">
                        <i class="fold iconfont icon-right"></i>
                        
                        开发
                        <small>(34)</small>
                        
                    </div>
                    
                        <ul class="sub hide">
                            
                                <li>
                                    <div data-rel="开发<--->框架">
                                        
                                        框架
                                        
                                            <small>(14
                                                )</small>
                                        
                                    </div>
                                    
                                </li>
                            
                                <li>
                                    <div data-rel="开发<--->其他">
                                        
                                        其他
                                        
                                            <small>(5
                                                )</small>
                                        
                                    </div>
                                    
                                </li>
                            
                                <li>
                                    <div data-rel="开发<--->数据库">
                                        
                                        数据库
                                        
                                            <small>(2
                                                )</small>
                                        
                                    </div>
                                    
                                </li>
                            
                                <li>
                                    <div data-rel="开发<--->疑难杂症">
                                        
                                        疑难杂症
                                        
                                            <small>(2
                                                )</small>
                                        
                                    </div>
                                    
                                </li>
                            
                                <li>
                                    <div data-rel="开发<--->中间件">
                                        
                                        中间件
                                        
                                            <small>(5
                                                )</small>
                                        
                                    </div>
                                    
                                </li>
                            
                                <li>
                                    <div data-rel="开发<--->Java">
                                        
                                        Java
                                        
                                            <small>(6
                                                )</small>
                                        
                                    </div>
                                    
                                </li>
                            
                        </ul>
                    
                </li>
            
        
    
        
            
        
    
        
            
        
    
        
            
        
    
        
            
        
    
        
            
        
    
        
            
        
    
</ul>
<div class="left-bottom">
    <div class="menus">
        
            
            
            
    </div>
    <div>
        
        
    </div>
</div>
<input type="hidden" id="yelog_site_posts_number" value="34">
<input type="hidden" id="yelog_site_word_count" value="83.6k">
<div style="display: none">
    <span id="busuanzi_value_site_uv"></span>
    <span id="busuanzi_value_site_pv"></span>
</div>

    </div>
    <div class="nav-right">
        <div class="friends-area">
    <div class="friends-title">
        Links
        <i class="iconfont icon-left"></i>
    </div>
    <div class="friends-content">
        <ul>
            
            <li><a target="_blank" href="https://xiaomaer-sss.gitee.io/">叶落阁</a></li>
            
        </ul>
    </div>
</div>
        <div class="title-list">
    <div class="right-top">
        <div id="default-panel">
            <i class="iconfont icon-search" data-title="搜索 快捷键 i"></i>
            <div class="right-title">All</div>
            <i class="iconfont icon-file-tree" data-title="切换到大纲视图 快捷键 w"></i>
        </div>
        <div id="search-panel">
            <i class="iconfont icon-left" data-title="返回"></i>
            <input id="local-search-input" autocomplete="off"/>
            <label class="border-line" for="input"></label>
            <i class="iconfont icon-case-sensitive" data-title="大小写敏感"></i>
            <i class="iconfont icon-tag" data-title="标签"></i>
        </div>
        <div id="outline-panel" style="display: none">
            <div class="right-title">大纲</div>
            <i class="iconfont icon-list" data-title="切换到文章列表"></i>
        </div>
    </div>

    <div class="tags-list">
    <input id="tag-search" />
    <div class="tag-wrapper">
        
            <li class="article-tag-list-item">
                <i class="iconfont icon-tag"></i><a>队列</a>
            </li>
        
            <li class="article-tag-list-item">
                <i class="iconfont icon-tag"></i><a>分布式</a>
            </li>
        
            <li class="article-tag-list-item">
                <i class="iconfont icon-tag"></i><a>缓存</a>
            </li>
        
            <li class="article-tag-list-item">
                <i class="iconfont icon-tag"></i><a>流式处理</a>
            </li>
        
            <li class="article-tag-list-item">
                <i class="iconfont icon-tag"></i><a>区块链</a>
            </li>
        
            <li class="article-tag-list-item">
                <i class="iconfont icon-tag"></i><a>实战面试题</a>
            </li>
        
            <li class="article-tag-list-item">
                <i class="iconfont icon-tag"></i><a>数据库</a>
            </li>
        
            <li class="article-tag-list-item">
                <i class="iconfont icon-tag"></i><a>异步</a>
            </li>
        
            <li class="article-tag-list-item">
                <i class="iconfont icon-tag"></i><a>Bug</a>
            </li>
        
            <li class="article-tag-list-item">
                <i class="iconfont icon-tag"></i><a>Docker</a>
            </li>
        
            <li class="article-tag-list-item">
                <i class="iconfont icon-tag"></i><a>Java</a>
            </li>
        
            <li class="article-tag-list-item">
                <i class="iconfont icon-tag"></i><a>Java-集合</a>
            </li>
        
            <li class="article-tag-list-item">
                <i class="iconfont icon-tag"></i><a>Java-进阶</a>
            </li>
        
            <li class="article-tag-list-item">
                <i class="iconfont icon-tag"></i><a>Java-JVM</a>
            </li>
        
            <li class="article-tag-list-item">
                <i class="iconfont icon-tag"></i><a>Java基础</a>
            </li>
        
            <li class="article-tag-list-item">
                <i class="iconfont icon-tag"></i><a>LB</a>
            </li>
        
            <li class="article-tag-list-item">
                <i class="iconfont icon-tag"></i><a>MQ</a>
            </li>
        
            <li class="article-tag-list-item">
                <i class="iconfont icon-tag"></i><a>Mybatis</a>
            </li>
        
            <li class="article-tag-list-item">
                <i class="iconfont icon-tag"></i><a>MySQL</a>
            </li>
        
            <li class="article-tag-list-item">
                <i class="iconfont icon-tag"></i><a>Redis</a>
            </li>
        
            <li class="article-tag-list-item">
                <i class="iconfont icon-tag"></i><a>Spring</a>
            </li>
        
            <li class="article-tag-list-item">
                <i class="iconfont icon-tag"></i><a>Spring Cloud Alibaba</a>
            </li>
        
            <li class="article-tag-list-item">
                <i class="iconfont icon-tag"></i><a>SpringBoot</a>
            </li>
        
    </div>

</div>

    
    <nav id="title-list-nav">
        
        
        <a  class="All 开发 中间件 "
           href="/xiaomaer-sss/2023/02/03/Rabbit%20MQ%EF%BC%88%E9%9D%A2%E8%AF%95%EF%BC%89/"
           data-tag="队列,异步"
           data-author="" >
            <span class="post-title" title="Rabbit MQ（面试）">Rabbit MQ（面试）</span>
            <span class="post-date" title="2023-02-03 21:04:21">2023/02/03</span>
        </a>
        
        
        <a  class="All 开发 Java "
           href="/xiaomaer-sss/2023/02/03/%E5%AE%9E%E6%88%98%E9%9D%A2%E8%AF%95%E9%A2%98%EF%BC%88%E9%9D%A2%E8%AF%95%EF%BC%89/"
           data-tag="实战面试题"
           data-author="" >
            <span class="post-title" title="实战面试题">实战面试题</span>
            <span class="post-date" title="2023-02-03 17:11:07">2023/02/03</span>
        </a>
        
        
        <a  class="All 开发 中间件 "
           href="/xiaomaer-sss/2023/02/02/Kafka%EF%BC%88%E9%9D%A2%E8%AF%95%EF%BC%89/"
           data-tag="分布式,流式处理,MQ"
           data-author="" >
            <span class="post-title" title="Kafka（面试）">Kafka（面试）</span>
            <span class="post-date" title="2023-02-02 09:51:06">2023/02/02</span>
        </a>
        
        
        <a  class="All 开发 中间件 "
           href="/xiaomaer-sss/2023/02/02/Zookeeper%EF%BC%88%E9%9D%A2%E8%AF%95%EF%BC%89/"
           data-tag="分布式"
           data-author="" >
            <span class="post-title" title="Zookeeper（面试）">Zookeeper（面试）</span>
            <span class="post-date" title="2023-02-02 09:50:33">2023/02/02</span>
        </a>
        
        
        <a  class="All 开发 中间件 "
           href="/xiaomaer-sss/2023/02/01/Redis%EF%BC%88%E9%9D%A2%E8%AF%95%EF%BC%89/"
           data-tag="Redis,缓存"
           data-author="" >
            <span class="post-title" title="Redis（面试）">Redis（面试）</span>
            <span class="post-date" title="2023-02-01 14:09:09">2023/02/01</span>
        </a>
        
        
        <a  class="All 开发 框架 "
           href="/xiaomaer-sss/2023/01/30/SpringBoot%EF%BC%88%E9%9D%A2%E8%AF%95%EF%BC%89/"
           data-tag="SpringBoot"
           data-author="" >
            <span class="post-title" title="SpringBoot（面试）">SpringBoot（面试）</span>
            <span class="post-date" title="2023-01-30 20:26:42">2023/01/30</span>
        </a>
        
        
        <a  class="All 开发 框架 "
           href="/xiaomaer-sss/2023/01/30/Mybatis%EF%BC%88%E9%9D%A2%E8%AF%95%EF%BC%89/"
           data-tag="Mybatis"
           data-author="" >
            <span class="post-title" title="Mybatis（面试）">Mybatis（面试）</span>
            <span class="post-date" title="2023-01-30 19:13:44">2023/01/30</span>
        </a>
        
        
        <a  class="All 开发 框架 "
           href="/xiaomaer-sss/2023/01/30/Spring%EF%BC%88%E9%9D%A2%E8%AF%95%EF%BC%89/"
           data-tag="Spring"
           data-author="" >
            <span class="post-title" title="Spring（面试）">Spring（面试）</span>
            <span class="post-date" title="2023-01-30 19:12:30">2023/01/30</span>
        </a>
        
        
        <a  class="All 开发 Java "
           href="/xiaomaer-sss/2023/01/29/Java-JVM%EF%BC%88%E9%9D%A2%E8%AF%95%EF%BC%89/"
           data-tag="Java-JVM"
           data-author="" >
            <span class="post-title" title="Java-JVM（面试）">Java-JVM（面试）</span>
            <span class="post-date" title="2023-01-29 16:31:34">2023/01/29</span>
        </a>
        
        
        <a  class="All 开发 Java "
           href="/xiaomaer-sss/2023/01/29/Java-%E8%BF%9B%E9%98%B6%EF%BC%88%E9%9D%A2%E8%AF%95%EF%BC%89/"
           data-tag="Java-进阶"
           data-author="" >
            <span class="post-title" title="Java-进阶（面试）">Java-进阶（面试）</span>
            <span class="post-date" title="2023-01-29 13:11:10">2023/01/29</span>
        </a>
        
        
        <a  class="All 开发 Java "
           href="/xiaomaer-sss/2023/01/29/Java-%E9%9B%86%E5%90%88%EF%BC%88%E9%9D%A2%E8%AF%95%EF%BC%89/"
           data-tag="Java-集合"
           data-author="" >
            <span class="post-title" title="Java-集合（面试）">Java-集合（面试）</span>
            <span class="post-date" title="2023-01-29 09:18:51">2023/01/29</span>
        </a>
        
        
        <a  class="All 开发 数据库 "
           href="/xiaomaer-sss/2023/01/28/%E6%95%B0%E6%8D%AE%E5%BA%93-MySQL%EF%BC%88%E9%9D%A2%E8%AF%95%EF%BC%89/"
           data-tag="MySQL"
           data-author="" >
            <span class="post-title" title="数据库-MySQL（面试）">数据库-MySQL（面试）</span>
            <span class="post-date" title="2023-01-28 16:50:59">2023/01/28</span>
        </a>
        
        
        <a  class="All 开发 Java "
           href="/xiaomaer-sss/2023/01/27/Java-%E5%9F%BA%E7%A1%80%EF%BC%88%E9%9D%A2%E8%AF%95%EF%BC%89/"
           data-tag="Java基础"
           data-author="" >
            <span class="post-title" title="Java-基础（面试）">Java-基础（面试）</span>
            <span class="post-date" title="2023-01-27 19:42:58">2023/01/27</span>
        </a>
        
        
        <a  class="All 开发 其他 "
           href="/xiaomaer-sss/2023/01/27/%E5%8C%BA%E5%9D%97%E9%93%BE%E9%92%B1%E5%8C%85/"
           data-tag="区块链"
           data-author="" >
            <span class="post-title" title="区块链钱包">区块链钱包</span>
            <span class="post-date" title="2023-01-27 18:57:51">2023/01/27</span>
        </a>
        
        
        <a  class="All 开发 其他 "
           href="/xiaomaer-sss/2023/01/27/Truffle%E5%B8%B8%E7%94%A8%E5%91%BD%E4%BB%A4/"
           data-tag="区块链"
           data-author="" >
            <span class="post-title" title="Truffle常用命令&amp;Web3常用方法">Truffle常用命令&amp;Web3常用方法</span>
            <span class="post-date" title="2023-01-27 18:57:51">2023/01/27</span>
        </a>
        
        
        <a  class="All 开发 其他 "
           href="/xiaomaer-sss/2023/01/27/Truffle&OpenZeppelin%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA/"
           data-tag="区块链"
           data-author="" >
            <span class="post-title" title="Truffle&amp;OpenZeppelin环境搭建">Truffle&amp;OpenZeppelin环境搭建</span>
            <span class="post-date" title="2023-01-27 18:57:51">2023/01/27</span>
        </a>
        
        
        <a  class="All 开发 其他 "
           href="/xiaomaer-sss/2023/01/27/Solidity/"
           data-tag="区块链"
           data-author="" >
            <span class="post-title" title="Solidity">Solidity</span>
            <span class="post-date" title="2023-01-27 18:57:51">2023/01/27</span>
        </a>
        
        
        <a  class="All 开发 中间件 "
           href="/xiaomaer-sss/2023/01/27/Nginx/"
           data-tag="LB"
           data-author="" >
            <span class="post-title" title="Nginx">Nginx</span>
            <span class="post-date" title="2023-01-27 18:57:51">2023/01/27</span>
        </a>
        
        
        <a  class="All 开发 框架 "
           href="/xiaomaer-sss/2023/01/27/DockerFile/"
           data-tag="Docker"
           data-author="" >
            <span class="post-title" title="Dockerfile">Dockerfile</span>
            <span class="post-date" title="2023-01-27 17:45:23">2023/01/27</span>
        </a>
        
        
        <a  class="All 开发 其他 "
           href="/xiaomaer-sss/2023/01/27/%E5%8C%BA%E5%9D%97%E9%93%BE%E4%B9%8B%E4%BB%A5%E5%A4%AA%E5%9D%8A/"
           data-tag="区块链"
           data-author="" >
            <span class="post-title" title="区块链之以太坊">区块链之以太坊</span>
            <span class="post-date" title="2023-01-27 17:45:23">2023/01/27</span>
        </a>
        
        
        <a  class="All 开发 数据库 "
           href="/xiaomaer-sss/2023/01/27/%E5%B8%B8%E7%94%A8SQL%E8%AF%AD%E6%B3%95%E6%95%B4%E7%90%86/"
           data-tag="MySQL,数据库"
           data-author="" >
            <span class="post-title" title="常用SQL语法整理">常用SQL语法整理</span>
            <span class="post-date" title="2023-01-27 17:45:23">2023/01/27</span>
        </a>
        
        
        <a  class="All 开发 框架 "
           href="/xiaomaer-sss/2023/01/27/docker%E8%BF%9B%E9%98%B6/"
           data-tag="Docker"
           data-author="" >
            <span class="post-title" title="Docker进阶">Docker进阶</span>
            <span class="post-date" title="2023-01-27 17:45:23">2023/01/27</span>
        </a>
        
        
        <a  class="All 开发 框架 "
           href="/xiaomaer-sss/2023/01/27/Docker%E5%9F%BA%E7%A1%80/"
           data-tag="Docker"
           data-author="" >
            <span class="post-title" title="Docker基础">Docker基础</span>
            <span class="post-date" title="2023-01-27 17:45:23">2023/01/27</span>
        </a>
        
        
        <a  class="All 开发 框架 "
           href="/xiaomaer-sss/2023/01/27/Docker%E5%AE%89%E8%A3%85%E5%B8%B8%E8%A7%81%E7%BB%84%E4%BB%B6/"
           data-tag="Docker"
           data-author="" >
            <span class="post-title" title="Docker安装常见组件">Docker安装常见组件</span>
            <span class="post-date" title="2023-01-27 17:45:23">2023/01/27</span>
        </a>
        
        
        <a  class="All 开发 框架 "
           href="/xiaomaer-sss/2023/01/26/SkyWalking/"
           data-tag="Spring Cloud Alibaba"
           data-author="" >
            <span class="post-title" title="SkyWalking">SkyWalking</span>
            <span class="post-date" title="2023-01-26 21:39:44">2023/01/26</span>
        </a>
        
        
        <a  class="All 开发 框架 "
           href="/xiaomaer-sss/2023/01/26/Sentinel/"
           data-tag="Spring Cloud Alibaba"
           data-author="" >
            <span class="post-title" title="Sentinel">Sentinel</span>
            <span class="post-date" title="2023-01-26 21:39:44">2023/01/26</span>
        </a>
        
        
        <a  class="All 开发 框架 "
           href="/xiaomaer-sss/2023/01/26/Seata/"
           data-tag="Spring Cloud Alibaba"
           data-author="" >
            <span class="post-title" title="Seata">Seata</span>
            <span class="post-date" title="2023-01-26 21:39:44">2023/01/26</span>
        </a>
        
        
        <a  class="All 开发 框架 "
           href="/xiaomaer-sss/2023/01/26/Ribbon/"
           data-tag="Spring Cloud Alibaba"
           data-author="" >
            <span class="post-title" title="Ribbon">Ribbon</span>
            <span class="post-date" title="2023-01-26 21:39:44">2023/01/26</span>
        </a>
        
        
        <a  class="All 开发 疑难杂症 "
           href="/xiaomaer-sss/2023/01/26/github%E6%8B%89%E5%8F%96%E4%BB%A3%E7%A0%81%E6%8A%A5%20git@github.com's%20password/"
           data-tag="Bug"
           data-author="" >
            <span class="post-title" title="github拉取代码报 &#34;git@github.com&#39;s password&#34;">github拉取代码报 &#34;git@github.com&#39;s password&#34;</span>
            <span class="post-date" title="2023-01-26 21:39:44">2023/01/26</span>
        </a>
        
        
        <a  class="All 开发 疑难杂症 "
           href="/xiaomaer-sss/2023/01/26/gitee%E6%90%AD%E5%BB%BA%E4%B8%AA%E4%BA%BA%E5%8D%9A%E5%AE%A2%E6%95%99%E7%A8%8B/"
           data-tag="Bug"
           data-author="" >
            <span class="post-title" title="gitee搭建个人博客教程">gitee搭建个人博客教程</span>
            <span class="post-date" title="2023-01-26 21:39:44">2023/01/26</span>
        </a>
        
        
        <a  class="All 开发 框架 "
           href="/xiaomaer-sss/2023/01/26/GateWay/"
           data-tag="Spring Cloud Alibaba"
           data-author="" >
            <span class="post-title" title="GateWay">GateWay</span>
            <span class="post-date" title="2023-01-26 21:39:44">2023/01/26</span>
        </a>
        
        
        <a  class="All 开发 框架 "
           href="/xiaomaer-sss/2023/01/26/Fegin/"
           data-tag="Spring Cloud Alibaba"
           data-author="" >
            <span class="post-title" title="Fegin">Fegin</span>
            <span class="post-date" title="2023-01-26 21:39:44">2023/01/26</span>
        </a>
        
        
        <a  class="All 开发 框架 "
           href="/xiaomaer-sss/2023/01/20/Nacos/"
           data-tag="Spring Cloud Alibaba"
           data-author="" >
            <span class="post-title" title="Nacos">Nacos</span>
            <span class="post-date" title="2023-01-20 17:12:00">2023/01/20</span>
        </a>
        
        
        <a  class="All 开发 Java "
           href="/xiaomaer-sss/2023/01/17/hello-world/"
           data-tag="Java"
           data-author="" >
            <span class="post-title" title="Hello World">Hello World</span>
            <span class="post-date" title="2023-01-17 15:40:39">2023/01/17</span>
        </a>
        
        <div id="no-item-tips">

        </div>
    </nav>
    <div id="outline-list">
    </div>
</div>

    </div>
    <div class="hide-list">
        <div class="semicircle" data-title="切换全屏 快捷键 s">
            <div class="brackets first"><</div>
            <div class="brackets">&gt;</div>
        </div>
    </div>
</aside>
<div id="post">
    <div class="pjax">
        <article id="post-Seata" class="article article-type-post" itemscope itemprop="blogPost">
    
        <h1 class="article-title">Seata</h1>
    
    <div class="article-meta">
        
        
        
        <span class="book">
            <i class="iconfont icon-category"></i>
            
            
            <a  data-rel="开发">开发</a> > 
            
            <a  data-rel="开发&lt;---&gt;框架">框架</a>
            
        </span>
        
        
        <span class="tag">
            <i class="iconfont icon-tag"></i>
            
            <a class="color1">Spring Cloud Alibaba</a>
            
        </span>
        
    </div>
    <div class="article-meta">
        
            Created At : <time class="date" title='Updated At: 2023-01-26 22:05:42'>2023-01-26 21:39</time>
        
    </div>
    <div class="article-meta">
        
        <span>Count:7k</span>
        
        
        <span id="busuanzi_container_page_pv">
            Views 👀 :<span id="busuanzi_value_page_pv">
                <span class="count-comment">
                    <span class="spinner">
                      <div class="cube1"></div>
                      <div class="cube2"></div>
                    </span>
                </span>
            </span>
        </span>
        
        
    </div>
    
    <div class="toc-ref">
    
        <ol class="toc"><li class="toc-item toc-level-1"><a class="toc-link" href="#%E4%BA%8B%E5%8A%A1"><span class="toc-text">事务</span></a></li><li class="toc-item toc-level-1"><a class="toc-link" href="#%E5%88%86%E5%B8%83%E5%BC%8F%E4%BA%8B%E5%8A%A1"><span class="toc-text">分布式事务</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%B8%B8%E8%A7%81%E5%88%86%E5%B8%83%E5%BC%8F%E4%BA%8B%E5%8A%A1%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88"><span class="toc-text">常见分布式事务解决方案</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#2PC%E4%B8%A4%E9%98%B6%E6%AE%B5%E6%8F%90%E4%BA%A4%E5%8D%8F%E8%AE%AE"><span class="toc-text">2PC两阶段提交协议</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#AT%E3%80%81TCC%E3%80%81Saga%E3%80%81XA%E5%9B%9B%E7%A7%8D%E4%BA%8B%E5%8A%A1%E6%A8%A1%E5%BC%8F"><span class="toc-text">AT、TCC、Saga、XA四种事务模式</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#AT%E3%80%81TCC%E3%80%81Saga%E3%80%81XA-%E5%9B%9B%E7%A7%8D%E6%A8%A1%E5%BC%8F%E6%80%BB%E7%BB%93"><span class="toc-text">AT、TCC、Saga、XA 四种模式总结</span></a></li></ol></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#Seata"><span class="toc-text">Seata</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#Seata%E7%9B%B8%E5%85%B3%E8%AE%BE%E8%AE%A1"><span class="toc-text">Seata相关设计</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E8%AE%BE%E8%AE%A1%E6%80%9D%E8%B7%AF"><span class="toc-text">设计思路</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E8%AE%BE%E8%AE%A1%E4%BA%AE%E7%82%B9"><span class="toc-text">设计亮点</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%AD%98%E5%9C%A8%E7%9A%84%E9%97%AE%E9%A2%98"><span class="toc-text">存在的问题</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#Seata%E4%BD%BF%E7%94%A8"><span class="toc-text">Seata使用</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#Seata-Server-TC-%E6%90%AD%E5%BB%BA"><span class="toc-text">Seata Server(TC)搭建</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E4%BF%AE%E6%94%B9Server%E7%AB%AF%E5%AD%98%E5%82%A8%E6%A8%A1%E5%BC%8F%EF%BC%88store-mode%EF%BC%89"><span class="toc-text">修改Server端存储模式（store.mode）</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Seata%E6%95%B4%E5%90%88nacos"><span class="toc-text">Seata整合nacos</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E4%BD%BF%E7%94%A8seata"><span class="toc-text">使用seata</span></a></li></ol></li></ol></li></ol></li></ol>
    
<style>
    .left-col .switch-btn,
    .left-col .switch-area {
        display: none;
    }
    .toc-level-3 i,
    .toc-level-3 ol {
        display: none !important;
    }
</style>
</div>
    
    <div class="article-entry" itemprop="articleBody">
      
        <p>学习seata之前，我们先要回顾一下事务和了解一下分布式事务相关的知识，有助于我们理解seata。seata service搭建完成后，使用起来是很简单的。</p>
<h1 id="事务"><a href="#事务" class="headerlink" title="事务"></a>事务</h1><p>事务(Transaction)是访问并可能更新数据库中各种数据项的一个程序执行单元(unit)。在关系数据 库中，一个事务由一组SQL语句组成。事务应该具有4个属性：原子性、一致性、隔离性、持久性。 这四个属性通常称为ACID特性。<br>任何事务机制在实现时，都应该考虑事务的ACID特性，包括：本地事务、分布式事务，即使不能都很好的满足，也要考虑支持到什么程度。 </p>
<ul>
<li><p><strong>原子性（Atomicity）</strong>：事务是一个不可分割的工作单位，事务中包括的诸多操作要么都做，要么都不做。   </p>
</li>
<li><p><strong>一致性（Consistency）</strong>：事务必须是使数据库从一个一致性状态变到另一个一致性状态，事务的中间状态不能被观察到的。   </p>
</li>
<li><p><strong>隔离性（Isolation）</strong>：一个事务的执行不能被其他事务干扰。即一个事务内部的操作及使用的数据对并发的其他事务是隔离的，并发执行的各个事务之间不能互相干扰。<br>隔离性又分为四个级别：</p>
<ul>
<li>读未提交(read uncommitted)</li>
<li>读已提交(read committed，解决脏读)</li>
<li>可重复读(repeatable read，解决虚读)</li>
<li>串行化(serializable，解决幻读)</li>
</ul>
</li>
<li><p><strong>持久性（Durability）</strong>：持久性也称永久性（permanence），指一个事务一旦提交，它对数据库 中数据的改变就应该是永久性的。接下来的其他操作或故障不应该对其有任何影响。 </p>
</li>
</ul>
<h1 id="分布式事务"><a href="#分布式事务" class="headerlink" title="分布式事务"></a>分布式事务</h1><p>完成某一个业务功能可能需要横跨多个服务，操作多个数据库。这就涉及到到了分布式事务，用需要操作的资源位于多个资源服务器上，而应用需要保证对于多个资源服务器的数据的操作，要么全部成 功，要么全部失败。本质上来说，分布式事务就是为了保证不同资源服务器的数据一致性。 </p>
<p>典型的分布式事务场景举例：</p>
<ul>
<li><p>跨库事务<br>一个应用某个功能需要操作多个库，不同的库中存储不同的业务数据 。</p>
</li>
<li><p>分库分表<br>通常一个库数据量比较大或者预期未来的数据量比较大，都会进行水平拆分 ，也就是分库分表的情况。<br>对于分库分表的情况，一般开发人员都会使用一些数据库中间件来降低sql操作的复杂性。如，对 于sql：insert into user(id,name) values (1,”张三”),(2,”李四”)。这条sql是操作单库的语法，单库情 况下，可以保证事务的一致性。但是由于现在进行了分库分表，开发人员希望将1号记录插入分库1，2号记录插入分库2。所以数据库中间件要将其改写为2条sql，分别插入两个不同的分库，此时要保证两个库要不都成功，要不都失败，因此基本上所有的数据库中间件都面临着分布式事务的问题。 </p>
</li>
<li><p>服务化<br>Service A完成某个功能需要直接操作数据库，同时需要调用Service B和Service C，而Service B又同时操作了2个数据库，Service C也操作了一个库。需要保证这些跨服务的对多个数据库的操作要不都成功，要不都失败。实际上这可能是最典型的分布式事务场景。</p>
</li>
</ul>
<h2 id="常见分布式事务解决方案"><a href="#常见分布式事务解决方案" class="headerlink" title="常见分布式事务解决方案"></a>常见分布式事务解决方案</h2><p>解决分布式事务，也有相对应的规范和协议。分布式事务相关的协议有2PC、3PC。由于三阶段提交协议3PC非常难实现，目前市面上主流的分布式事务解决方案都是基于2PC。</p>
<ol>
<li>seata</li>
<li>消息队列</li>
<li>saga</li>
<li>XA</li>
</ol>
<p>他们有一个共同点，都是两阶段提交协议（2PC）。两阶段是指完成整个分布式事务划分成两个步骤完成。上面常见的分布式事务解决方案，分别对应着<strong>分布式事务的四种模式</strong>：AT、TCC、Saga、XA。 四种分布式事务模式，都有各自的理论基础，分别在不同的时间被提出。每种模式都有它的适用场景，同样每个模式也都诞生有各自的代表产品。而这些代表产品，可能就是我们常见的(全局事务、 基于可靠消息、最大努力通知、TCC)。 </p>
<h2 id="2PC两阶段提交协议"><a href="#2PC两阶段提交协议" class="headerlink" title="2PC两阶段提交协议"></a>2PC两阶段提交协议</h2><p>2PC（Two-Phase Commit）两阶段提交协议，顾名思义，分为两个阶段：Prepare和Commit</p>
<p><strong>Prepare：提交事务请求</strong></p>
<p>大概流程如下：</p>
<p><img src="https://gitee.com/xiaomaer-sss/picgo/raw/master/images/2023/1672906269598.png" alt="1672906269598"></p>
<ol>
<li>询问——协调者向所有参与者发送事务请求，询问是否可以执行事务操作，然后等待所有参与者的响应。</li>
<li>执行——所有参与者接受到协调者事务请求后，所有参与者执行事务操作（例如更新插入等操作），并将Undo和Redo信息记录在事务日志中。</li>
<li>响应——如果所有参与者成功的执行了事务并写入了Undo和Redo信息，则向协调者返回YES，否则返回NO。此时参与者如果宕机，就不会有任何响应给协调者。</li>
</ol>
<p><strong>Commit：执行事务提交</strong></p>
<p>执行事务提交分为两种情况，正常提交和中断。</p>
<ul>
<li><p>正常提交事务</p>
<p><img src="https://gitee.com/xiaomaer-sss/picgo/raw/master/images/2023/1672906820927.png" alt="1672906820927"></p>
<ol>
<li>commit——协调者向所有参与者发送Commit请求。</li>
<li>事务提交——参与者收到Commit请求后，执行事务提交，提交完成后释放事务执行期间占有的所有资源。</li>
<li>反馈结果——参与者执行事务提交后向协调者发送ACK响应。</li>
<li>完成事务——接收到所有参与者的ACK响应后，完成事务提交。</li>
</ol>
</li>
<li><p>中断事务</p>
</li>
</ul>
<p>在执行Prepare 步骤过程中，如果某些参与者执行事务失败、宕机或与协调者之间的网络中断，那么协调者就无法 收到所有参与者的YES响应，或者某个参与者返回了 No 响应，此时，协调者就会进入回退流程，对事务进行回 退。流程如下图红色部分(将 Commit 请求替换为红色的 Rollback 请求)： </p>
<p><img src="https://gitee.com/xiaomaer-sss/picgo/raw/master/images/2023/1672908817074.png" alt="1672908817074"></p>
<ol>
<li>Rollback——协调者向所有参与者发送 Rollback 请求。</li>
<li>事务回滚——参与者收到 Rollback 后，使用 Prepare 阶段的Undo日志执行事务回滚，完成后释放事务执行 期占用的所有资源。</li>
<li>反馈结果——参与者执行事务回滚后向协调者发送 Ack 响应。</li>
<li>中断事务——接收到所有参与者的ACK响应后，完成事务中断。</li>
</ol>
<p><strong>2PC的弊端：</strong></p>
<ol>
<li>同步阻塞，参与者在等待协调者的指令时，其实是在等待其他参与者的响应，在此过程中，参与者是无法进 行其他操作的，也就是阻塞了其运行。 倘若参与者与协调者之间网络异常导致参与者一直收不到协调者信 息，那么会导致参与者一直阻塞下去。 </li>
<li>单点在2PC中，一切请求都来自协调者，所以协调者的地位是至关重要的，如果协调者宕机，那么就会使参与者一直阻塞并一直占用事务资源。 如果协调者也是分布式，使用选主方式提供服务，那么在一个协调者挂掉后，可以选取另一个协调者继续后续的服务，可以解决单点问题。但是，新协调者无法知道上一个事务的全部状态信息(例如已等待Prepare响应的时长等)，所以也无法顺利处理上一个事务。 </li>
<li>数据不一致，Commit事务过程中Commit请求/Rollback 请求可能因为协调者宕机或协调者与参与者网络问题丢失，那么就导致了部分参与者没有收到Commit/Rollback请求，而其他参与者则正常收到执行了Commit/Rollback 操作，没有收到请求的参与者则继续阻塞。这时，参与者之间的数据就不再一致了。 当参与者执行Commit/Rollback后会向协调者发送ACK，然而协调者不论是否收到所有的参与者的ACK，该事务也不会再有其他补救措施了，协调者能做的也就是等待超时后像事务发起者返回一个“我不确定该事务是否成   功”。 </li>
<li>环境可靠性依赖协调者Prepare请求发出后，等待响应，然而如果有参与者宕机或与协调者之间的网络中断，都会导致协调者无法收到所有参与者的响应，那么在 2PC 中，协调者会等待一定时间，然后超时后， 会触发事务中断，在这个过程中，协调者和所有其他参与者都是出于阻塞的。这种机制对网络问题常见的现实环境来说太苛刻了。  </li>
</ol>
<h3 id="AT、TCC、Saga、XA四种事务模式"><a href="#AT、TCC、Saga、XA四种事务模式" class="headerlink" title="AT、TCC、Saga、XA四种事务模式"></a>AT、TCC、Saga、XA四种事务模式</h3><ul>
<li><p><strong>AT模式（Auto Transcation）</strong><br>AT模式是一种无侵入的分布式事务解决方案。阿里的seata框架实现了该模式。在AT模式下，用户只需要关注自己的业务SQL，用户的业务SQL作为一阶段，seata框架会自动生成事务的二阶段提交和回滚操作。</p>
<p><img src="https://gitee.com/xiaomaer-sss/picgo/raw/master/images/2023/1672920303769.png" alt="1672920303769"></p>
<p>一阶段：</p>
<p>在一阶段，Seata会拦截“业务 SQL”，首先解析SQL语义，找到“业务 SQL”要更新的业务数据，在业务数据被更新前，将其保存成“before image”，然后执行“业务 SQL”更新业务数据， 在业务数据更新之后，再将其保存成“after image”，最后生成行锁。以上操作全部在一个数据库事务内完成，这样保证了一阶段操作的原子性。 </p>
<p><img src="https://gitee.com/xiaomaer-sss/picgo/raw/master/images/2023/1672920404447.png" alt="1672920404447"></p>
<p>二阶段提交：</p>
<p>二阶段如果是提交的话，因为“业务 SQL”在一阶段已经提交至数据库， 所以Seata框架只需将一 阶段保存的快照数据和行锁删掉，完成数据清理即可。 </p>
<p><img src="https://gitee.com/xiaomaer-sss/picgo/raw/master/images/2023/1672920614973.png" alt="1672920614973"></p>
<p>二阶段回滚：</p>
<p>二阶段如果是回滚的话，Seata就需要回滚一阶段已经执行的“业务 SQL”，还原业务数据。回滚方式便是用“before image”还原业务数据。但在还原前要首先要校验脏写，对比“数据库当前业务数据”和 “after image”，如果两份数据完全一致就说明没有脏写，可以还原业务数据，如果不一 致就说明有脏写，出现脏写就需要转人工处理。 </p>
<p><img src="https://gitee.com/xiaomaer-sss/picgo/raw/master/images/2023/1672920701848.png" alt="1672920701848"></p>
<p><strong>AT模式的一阶段、二阶段提交和回滚均由Seata框架自动生成，用户只需编写“业务 SQL”，便能轻松接入分布式事务，AT 模式是一种对业务无任何侵入的分布式事务解决方案。</strong> </p>
</li>
<li><p><strong>TCC模式（Try Commit Cancel）</strong><br>TCC模式入侵性比较强，并且得自己实现相关事务控制逻辑。但是，在整个过程中基本没有锁，所以性能更强。</p>
<p>常见的TCC模式框架：BeyeTCC、TCC-transction、Himly</p>
<p>TCC模式需要用户根据自己的业务场景实现Try、Confirm和Cancel三个操作。事务发起方在一阶段执行Try方式，在二阶段提交执行Confirm方法，二阶段回滚执行Cancel方法。<br><img src="https://gitee.com/xiaomaer-sss/picgo/raw/master/images/2023/1672921486181.png" alt="1672921486181"></p>
<p>TCC 三个方法描述： </p>
<ul>
<li><p>Try：资源的检测和预留</p>
</li>
<li><p>Confirm：执行的业务操作提交。要求Try成功Confirm一定要能成功</p>
</li>
<li><p>Cancel：预留资源释放</p>
</li>
</ul>
</li>
<li><p><strong>Saga模式</strong><br>补偿协议：业务流程中每个参与者都提交本地事务，当出现某一个参与者失败则补偿前面已经成功的参与者。一阶段正向服务和二阶段补偿服务都由业务开发实现。<br>saga模式的实现，是长事务解决方案。saga是一种补偿协议，在saga模式下，分布式事务内有多个参与者，每一个参与者都是一个冲正补偿服务，需要用户根据业务场景实现其正向操作和逆向回滚操作。<br><img src="https://gitee.com/xiaomaer-sss/picgo/raw/master/images/2023/1672921772548.png" alt="1672921772548"><br>如图：T1-Tn都是正向业务流程，都对应着一个冲正逆向操作C1-C3</p>
<p><strong>逻辑如下：</strong>分布式事务执行过程中，依次执行各参与者的正向操作，如果所有正向操作均执行成功，那么分布式事务提交。如果任何一个正向操作执行失败，那么分布式事务会退回去执行前面各参与者的逆向回滚操作，回滚已提交的参与者，使分布式事务回到初始状态。 Saga 正向服务与补偿服务也需要业务开发者实现。因此是业务入侵的。 Saga 模式下分布式事务通常是由事件驱动的，各个参与者之间是异步执行的，Saga 模式是一种长事务解决方案。 </p>
<p><strong>saga模式适用场景</strong><br>Saga模式适用于业务流程长且需要保证事务最终一致性的业务系统，Saga模式一阶段就会提交本地事务，无锁、长流程情况下可以保证性能。 事务参与者可能是其它公司的服务或者是遗留系统的服务，无法进行改造和提供TCC要求的接口，可以使用 Saga 模式。 </p>
<p><strong>saga模式的优缺点</strong></p>
<p>优点：</p>
<ul>
<li>一阶段提交本地数据库事务，无锁，高性能</li>
<li>参与者可以采用事务驱动异步执行，高吞吐</li>
<li>补偿服务即正向服务的“反向”，易于理解，易于实现</li>
</ul>
<p>缺点：</p>
<p>​    Saga模式由于一阶段已经提交本地数据库事务，且没有进行“预留”动作，所以不能保证隔离性。 </p>
</li>
<li><p><strong>XA模式</strong><br>在XA模式下，需要有一个[全局]协调器，每一个数据库事务完成后，进行第一阶段预提交，并通知协调器，把结果给协调器。协调器等所有分支事务操作完成、都预提交后，进行第二步。第二步协调器通知每个数据库进行逐个commit/rollback。其中，这个全局协调器就是XA模型中的TM角色，每个分支事务各自的数据库就是RM。</p>
<p> XA模式缺点：事务粒度大。高并发下，系统可用性低。因此很少使用。 </p>
</li>
</ul>
<h3 id="AT、TCC、Saga、XA-四种模式总结"><a href="#AT、TCC、Saga、XA-四种模式总结" class="headerlink" title="AT、TCC、Saga、XA 四种模式总结"></a>AT、TCC、Saga、XA 四种模式总结</h3><p>四种分布式事务模式，分别在不同的时间被提出，每种模式都有它的适用场景。</p>
<ul>
<li><p>AT模式是<strong>无侵入</strong>的分布式事务解决方案，适用于不希望对业务进行改造的场景，几乎0学 习成本。</p>
</li>
<li><p>TCC模式是高性能分布式事务解决方案，适用于核心系统等对<strong>性能有很高</strong>要求的场景。</p>
</li>
<li><p>Saga 模式是长事务解决方案，适用于业务流程长且需要保证事务<strong>最终一致性</strong>的业务系统， Saga 模式一阶段就会提交本地事务，无锁，长流程情况下可以保证性能，多用于渠道层、集成层业务系统。事务参与者可能是其它公司的服务或者是遗留系统的服务，无法进行改造和提供TCC要求的接口，也可以使用 Saga 模式。</p>
</li>
<li><p>XA模式是分布式<strong>强一致性</strong>的解决方案，但性能低而使用较少。 </p>
</li>
</ul>
<p>分布式事务本身就是一个技术难题，业务中具体使用哪种方案还是需要不同的业务特点自行选择。但是，我们也会发现，分布式事务会大大的提高流程的复杂度，会带来很多额外的开销工作（代码量上 去了，业务复杂了，性能下跌了）。 <strong>所以，当我们真实开发的过程中，能不使用分布式事务就不使用。</strong> </p>
<h1 id="Seata"><a href="#Seata" class="headerlink" title="Seata"></a>Seata</h1><p> Seata 是一款开源的分布式事务解决方案，致力于提供高性能和简单易用的分布式事务服务。Seata将为用户提供了 AT、TCC、Saga 和 XA 事务模式，AT模式是阿里首推的模式 。</p>
<p>相关官方文档：</p>
<p>官网：<a target="_blank" rel="noopener" href="https://seata.io/zh-cn/index.html">https://seata.io/zh-cn/index.html</a> </p>
<p>源码: <a target="_blank" rel="noopener" href="https://github.com/seata/seata">https://github.com/seata/seata</a> </p>
<p>官方Demo: <a target="_blank" rel="noopener" href="https://github.com/seata/seata-samples">https://github.com/seata/seata-samples</a> </p>
<h2 id="Seata相关设计"><a href="#Seata相关设计" class="headerlink" title="Seata相关设计"></a>Seata相关设计</h2><p>在 Seata 的架构中，一共有三个角色。其中，<strong>TC为单独部署的Server服务端，TM和RM为嵌入到应用中的 Client 客户端。</strong> </p>
<ol>
<li><p><strong>TC (Transaction Coordinator) - 事务协调者</strong><br>维护全局和分支事务的状态，驱动全局事务提交或回滚。</p>
</li>
<li><p><strong>TM (Transaction Manager) - 事务管理器</strong><br>定义全局事务的范围：开始全局事务、提交或回滚全局事务。</p>
</li>
<li><p><strong>RM (Resource Manager) - 资源管理器</strong><br>管理分支事务处理的资源，与TC交谈以注册分支事务和报告分支事务的状态，并驱动分支事务提交或回滚。</p>
</li>
</ol>
<p> 在 Seata 中，一个分布式事务的生命周期如下：</p>
<p><img src="https://gitee.com/xiaomaer-sss/picgo/raw/master/images/2023/1672923660704.png" alt="1672923660704"></p>
<ol>
<li><p>TM请求TC开启一个全局事务。TC 会生成一个XID作为该全局事务的编号。XID会在微服务的调用链路中传播，保证将多个微服务的子事务关联在一起。 当一进入事务方法中就会生成XID。global_table表中就是存储的全局事务信息</p>
</li>
<li><p>RM请求TC将本地事务注册为全局事务的分支事务，通过全局事务的XID进行关联。当运行数据库操作方法，branch_table表中存储事务参与者信息</p>
</li>
<li><p>TM请求TC告诉XID对应的全局事务是进行提交还是回滚。</p>
</li>
<li><p>TC驱动RM们将XID对应的自己的本地事务进行提交还是回滚。</p>
</li>
</ol>
<h3 id="设计思路"><a href="#设计思路" class="headerlink" title="设计思路"></a>设计思路</h3><p>AT模式的核心是对业务无入侵，是一种改进后的二阶段提交。设计思路如下：</p>
<p><strong>第一阶段</strong></p>
<p>业务数据和回滚日志记录在同一个本地事务中提交，释放本地锁和连接资源。核心在于对业务sql进行解析，转换成undolog，并同时入库。</p>
<p><img src="https://gitee.com/xiaomaer-sss/picgo/raw/master/images/2023/1672990783336.png" alt="1672990783336"></p>
<p><strong>第二阶段</strong></p>
<p> 分布式事务操作<strong>成功</strong>，则TC通知RM异步删除undolog </p>
<p><img src="https://gitee.com/xiaomaer-sss/picgo/raw/master/images/2023/1672990909399.png" alt="1672990909399"></p>
<p>分布式事务操作<strong>失败</strong>，TM向TC发送回滚请求，RM收到协调器TC发来的回滚请求，通过XID和Branch ID找到相应的回滚日志记 录，通过回滚记录生成反向的更新SQL并执行（执行前会将before image和after image进行对比），然后删除事务占用的资源。完成分支的回滚。 </p>
<p><img src="https://gitee.com/xiaomaer-sss/picgo/raw/master/images/2023/1672991418164.png" alt="1672991418164"></p>
<h3 id="设计亮点"><a href="#设计亮点" class="headerlink" title="设计亮点"></a>设计亮点</h3><ol>
<li>应用层基于SQL解析实现了自动补偿，从而最大程度的降低业务侵入性。</li>
<li>将分布式事务中TC（事务协调者）独立部署，负责事务的注册、回滚。</li>
<li>通过全局锁实现了写隔离与读隔离。 </li>
</ol>
<h3 id="存在的问题"><a href="#存在的问题" class="headerlink" title="存在的问题"></a>存在的问题</h3><ul>
<li><p>性能损耗</p>
<p>一条Update的SQL，则需要全局事务xid获取（与TC通讯）、before image（解析SQL，查询一次数据库）、after image（查询一 次数据库）、insert undo log（写一次数据库）、before commit（与TC通讯，判断锁冲突），这些操作都需要一次远程通讯RPC，而且是同步的。另外undo log写入时blob字段的插入性能也是不高的。每条写SQL都会增加这么多开销,粗略估计会增加5倍响应时间。</p>
</li>
<li><p>性价比</p>
<p>为了进行自动补偿，需要对所有交易生成前后镜像并持久化，可是在实际业务场景下，这个是成功率有多高，或者说分布式事务失败需要回滚的有多少比率？按照二八原则预估，为了20%的交易回滚，需要将80%的成功交易的响应时间增加5倍，这样的代价相比于让应用开发一个补偿交易是否是值得？</p>
</li>
<li><p>热点数据</p>
<p>相比XA，Seata虽然在一阶段成功后会释放数据库锁，但一阶段在commit前全局锁的判定也拉长了对数据锁的占有时间，这个开销比XA的prepare低多少需要根据实际业务场景进行测试。全局锁的引入实现了隔离性，但带来的问题就是阻塞，降低并发性，尤其是热点数据，这个问题会更加严重。</p>
</li>
<li><p>回滚锁释放时间</p>
<p>Seata在回滚时，需要先删除各节点的undo log，然后才能释放TC内存中的锁，所以如果第二阶段是回滚，释放锁的时间会更长。</p>
</li>
<li><p>死锁问题</p>
<p>Seata的引入全局锁会额外增加死锁的风险，但如果出现死锁，会不断进行重试，最后靠等待全局锁超时，这种方式并不优雅，也延长了对数据库锁的占有时间。 </p>
</li>
</ul>
<h2 id="Seata使用"><a href="#Seata使用" class="headerlink" title="Seata使用"></a>Seata使用</h2><p>使用Seata需要单独部署Seata的服务，配置中心等。在服务中也需要创建相关表。相关构建可能会有点复杂，但是用是需要使用一个@GlobalTransaction注解就好。</p>
<p>这次是在本地win上搭建，在linux上搭建需要修改的配置文件和win差不多。后期有机会再在linux上部署一下。</p>
<h3 id="Seata-Server-TC-搭建"><a href="#Seata-Server-TC-搭建" class="headerlink" title="Seata Server(TC)搭建"></a>Seata Server(TC)搭建</h3><p>Seata服务端下载地址：</p>
<p> <a target="_blank" rel="noopener" href="https://github.com/seata/seata/releases">https://github.com/seata/seata/releases</a></p>
<p>结合自己项目的spring cloud alibaba版本选择合适的Seata版本。我这边使用的是seata-server-1.3.0</p>
<p><img src="https://gitee.com/xiaomaer-sss/picgo/raw/master/images/2023/1672993215444.png" alt="1672993215444"></p>
<p>下载完成后，解压即可。接下来就是修改配置了。</p>
<h4 id="修改Server端存储模式（store-mode）"><a href="#修改Server端存储模式（store-mode）" class="headerlink" title="修改Server端存储模式（store.mode）"></a>修改Server端存储模式（store.mode）</h4><p>Server端支持三种存储模式：</p>
<ol>
<li>file：默认模式，<strong>单机模式</strong>。全局事务会话信息存在内存中，读写并持久化到本地文件root.data中。性能较高。</li>
<li>db：要求mysql5.7+，高可用模式。全局事务会话信息通过db共享，性能稍差一些。</li>
<li>redis：Seata-Server1.3及以上斑斑支持，性能较高，但是存在事务信息丢失的风险。建议提前配置适当的当前场景的redis持久化配置。</li>
</ol>
<p>这边使用db模式演示，具体操作如下：</p>
<ul>
<li><strong>修改seata\conf\file.conf文件</strong><br><img src="https://gitee.com/xiaomaer-sss/picgo/raw/master/images/2023/1673056874320.png" alt="1673056874320"></li>
<li><strong>创建数据库</strong><br>根据上一步中的配置文件中的配置，建立对应的数据库<br><img src="https://gitee.com/xiaomaer-sss/picgo/raw/master/images/2023/1673057010944.png" alt="1673057010944"></li>
<li><strong>创建表</strong></li>
</ul>
<p>数据库脚本可以在官方文档——&gt;运维指南——&gt;部署——&gt;新人文档——&gt;资源目录介绍，点击查看处获取。注意这里部署的是server端。</p>
<p><a target="_blank" rel="noopener" href="https://github.com/seata/seata/blob/1.4.0/script/server/db/mysql.sql">https://github.com/seata/seata/blob/1.4.0/script/server/db/mysql.sql</a><br><img src="https://gitee.com/xiaomaer-sss/picgo/raw/master/images/2023/1673058622075.png" alt="1673058622075"></p>
<h4 id="Seata整合nacos"><a href="#Seata整合nacos" class="headerlink" title="Seata整合nacos"></a>Seata整合nacos</h4><ul>
<li><p><strong>整合注册中心</strong></p>
<p>说明：这两项配置可以更改负载均衡模式</p>
<p>loadBalance = “RandomLoadBalance”</p>
<p>loadBalanceVirtualNode = 10</p>
<p> loadBalanceVirtualNode = 10</p>
<p><img src="https://gitee.com/xiaomaer-sss/picgo/raw/master/images/2023/1673060349565.png" alt="1673060349565"></p>
</li>
<li><p><strong>整合配置中心</strong></p>
</li>
</ul>
<p><img src="https://gitee.com/xiaomaer-sss/picgo/raw/master/images/2023/1673060831095.png" alt="1673060831095"></p>
<p>​    <strong>注意：</strong>如果seata-server使用了nacos作为配置中心，配置信息就会从nacos中读取。配置registry.conf使用nacos时，group配置要和seata-server中的group一样。</p>
<ul>
<li><p><strong>修改seata配置中心信息</strong></p>
<p>先从seata官网（<a target="_blank" rel="noopener" href="https://github.com/seata/seata/tree/1.4.0%EF%BC%89%E8%8E%B7%E5%8F%96seata%E6%BA%90%E7%A0%81%E5%B7%A5%E7%A8%8B%E7%9A%84%E5%8E%8B%E7%BC%A9%E6%96%87%E4%BB%B6%EF%BC%8C%E7%84%B6%E5%90%8E%E8%8E%B7%E5%8F%96seata-1.4.0/script/config-center/config.txt%E5%B9%B6%E4%BF%AE%E6%94%B9%E9%83%A8%E5%88%86%E9%85%8D%E7%BD%AE">https://github.com/seata/seata/tree/1.4.0）获取seata源码工程的压缩文件，然后获取seata-1.4.0\script\config-center\config.txt并修改部分配置</a></p>
</li>
</ul>
<p><img src="https://gitee.com/xiaomaer-sss/picgo/raw/master/images/2023/1673141100333.png" alt="1673141100333"></p>
<p><strong>seata-1.4.0\script\config-center\config.txt文件中的一些说明：</strong></p>
<pre><code class="yml">service.vgroupMapping.my_test_tx_group=default
</code></pre>
<ol>
<li><p>使用了seata的客户端需要和my_test_tx_group保存一致。my_test_tx_group也可以自定义为guangzhou、shanghai等这样根据服务器地域进行命名（本次配置中使用的是”service.vgroupMapping.guangzhou=default”），可以用作异地灾备的一个配置。那么对应的客户端就要如下配置</p>
<pre><code>spring.cloud.alibaba.seata.tx_service_group=guangzhou
</code></pre>
</li>
<li><p>default需要等于registry.confi中registry配置中的cluster对应的值<br><img src="https://gitee.com/xiaomaer-sss/picgo/raw/master/images/2023/1673141862538.png" alt="1673141862538"></p>
</li>
</ol>
<ul>
<li><p><strong>同步配置参数到nacos</strong></p>
<p>在seata-1.4.0\script\config-center\nacos下运行以下脚本</p>
<pre><code class="shell">sh nacos-config.sh -h 192.168.2.7 -p 8848 -g SEATA_GROUP -t 8375c8f1-32d7-4d34-80f0-4ff80378c437 -u nacos -w nacos
# 相关参数说明：
# -h nacos主机host，默认值localhost
# -p nacos服务port，默认值8848
# -g 配置的分组，默认值SEATA_GROUP
# -t 租户信息，对应nacos中的namespaceID 默认为nacos的public
# -u nacos登录名，需要有读写权限
# -w 对应登录名的密码
</code></pre>
<p><img src="https://gitee.com/xiaomaer-sss/picgo/raw/master/images/2023/1673144622804.png" alt="1673144622804"></p>
</li>
</ul>
<p>然后就可以在nacos配置中心看到这些配置。</p>
<p><img src="https://gitee.com/xiaomaer-sss/picgo/raw/master/images/2023/1673144738120.png" alt="1673144738120"></p>
<ul>
<li><strong>启动seata-server服务</strong></li>
</ul>
<pre><code class="bash">seata/bin/seata-server.sh -h 127.0.0.1 -p 8091 -m db -n 1 -e test
</code></pre>
<p>参数说明：</p>
<table>
<thead>
<tr>
<th>参数</th>
<th>全写</th>
<th>作用</th>
<th>备注</th>
</tr>
</thead>
<tbody><tr>
<td>-h</td>
<td>–host</td>
<td>指定在注册中心中注册的IP</td>
<td>不指定时获取当前的IP，外部访问部署在云环境和容器中时建议指定</td>
</tr>
<tr>
<td>-p</td>
<td>–port</td>
<td>指定server启动的端口</td>
<td>默认为8091</td>
</tr>
<tr>
<td>-m</td>
<td>–storeMode</td>
<td>事务日志存储方式</td>
<td>支持file,db,redis(需要seata-server1.3+)。默认为file</td>
</tr>
<tr>
<td>-n</td>
<td>serverNode</td>
<td>用于指定seata-server节点ID</td>
<td>如1,2,3,…默认为1</td>
</tr>
<tr>
<td>-e</td>
<td>seataEvn</td>
<td>指定seate-server运行环境</td>
<td>如dev，test等，服务启动时会使用registry-dev.conf这样的配置</td>
</tr>
</tbody></table>
<p>集群部署：</p>
<p>seata集群的方式在win下不是很好部署。在linux下部署很方便，因为它不像nacos一样还需使用nginx来负载，seata直接使用nacos的LB。</p>
<pre><code class="bash"># 机器1
seata/bin/seata-server.sh -h 127.0.0.1 -p 8091 -m db -n 1 -e test
# 机器2
seata/bin/seata-server.sh -h 127.0.0.1 -p 8092 -m db -n 2 -e test
# 机器3
seata/bin/seata-server.sh -h 127.0.0.1 -p 8093 -m db -n 3 -e test
</code></pre>
<p>双击seata\bin下seata-server.bat启动Seata server。</p>
<p><img src="https://gitee.com/xiaomaer-sss/picgo/raw/master/images/2023/1673172386244.png" alt="1673172386244"></p>
<p>在启动seata server服务时遇到了一个Could not create connection to database server报错，已经解决了，可移步<a target="_blank" rel="noopener" href="https://blog.csdn.net/weixin_45340300/article/details/128602694?spm=1001.2014.3001.5501">查看</a></p>
<h4 id="使用seata"><a href="#使用seata" class="headerlink" title="使用seata"></a>使用seata</h4><p>下面的操作都是基于上一步的部署成功的seata server服务中进行。</p>
<ul>
<li><p>添加依赖<br>在使用到分布式事务的服务pom文件下添加seata依赖。</p>
<pre><code class="pom">&lt;dependency&gt;
    &lt;groupId&gt;com.alibaba.cloud&lt;/groupId&gt;
    &lt;artifactId&gt;spring-cloud-starter-alibaba-seata&lt;/artifactId&gt;
&lt;/dependency&gt;
</code></pre>
</li>
<li><p>创建undo_log表<br>在使用到分布式事务的服务对应的数据库中添加undo_log表，脚本如下：</p>
<pre><code class="sql">CREATE TABLE `undo_log` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `branch_id` bigint(20) NOT NULL,
  `xid` varchar(100) NOT NULL,
  `context` varchar(128) NOT NULL,
  `rollback_info` longblob NOT NULL,
  `log_status` int(11) NOT NULL,
  `log_created` datetime NOT NULL,
  `log_modified` datetime NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
</code></pre>
</li>
<li><p>添加配置文件<br>在使用到分布式事务的服务配置文件中添加seata相关配置。</p>
<pre><code class="yml"># 数据源
spring:
  datasource:
    username: root
    password: password
    url: jdbc:mysql://localhost:3306/seata_order?characterEncoding=utf8&amp;useSSL=false&amp;serverTimezone=UTC&amp;
    driver-class-name: com.mysql.cj.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource

    #初始化时运行sql脚本
    schema: classpath:sql/schema.sql
    initialization-mode: never
  application:
    name: alibaba-order-seata
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.2.7:8848
        username: nacos
        password: nacos
    alibaba:
      seata:
        tx-service-group: guangzhou #配置事务分组 看下自己配置中心的事务分组名称是啥
#设置mybatis
mybatis:
  mapper-locations: classpath:com/kiwi/order/mapper/*Mapper.xml
  #config-location: classpath:mybatis-config.xml
  typeAliasesPackage: com.kiwi.order.pojo
  configuration:
    mapUnderscoreToCamelCase: true
server:
  port: 8072
seata:
  registry:
    # 配置seata的注册中心， 告诉seata client 怎么去访问seata server(TC)
    type: nacos
    nacos:
      server-addr: 192.168.2.7:8848  # seata server 所在的nacos服务地址
      application: seata-server    # seata server 的服务名seata-server ，如果没有修改可以不配
      username: nacos
      password: nacos
      group: SEATA_GROUP          # seata server 所在的组，默认就是SEATA_GROUP，没有改也可以不配
      namespace: 8375c8f1-32d7-4d34-80f0-4ff80378c437 # 自己seata注册中心namespace
  config:
    type: nacos
    nacos:
      server-addr: 192.168.2.7:8848
      username: nacos
      password: nacos
      group: SEATA_GROUP
      namespace: 8375c8f1-32d7-4d34-80f0-4ff80378c437  # 自己seata配置中心namespace
</code></pre>
</li>
<li><p>使用@GlobalTransaction注解<br>在存在分布式事务的方法上添加@GlobalTransaction注解。</p>
<pre><code class="java">@GlobalTransactional
    @Override
    public Order create(Order order) &#123;
        // 插入能否成功？
        orderMapper.insert(order);

        // 扣减库存 能否成功？
        stockService.reduct(order.getProductId());

        // 异常
        int a=1/0;

        return order;
    &#125;
</code></pre>
</li>
</ul>
<p>启动服务，测试发生异常的回滚效果：</p>
<p>接口是访问不了</p>
<p><img src="https://gitee.com/xiaomaer-sss/picgo/raw/master/images/2023/1673274323535.png" alt="1673274323535"></p>
<p>控制台报错</p>
<p><img src="https://gitee.com/xiaomaer-sss/picgo/raw/master/images/2023/1673274365326.png" alt="1673274365326"></p>
<p>库存服务数据库数据未扣减，分布式事务生效。</p>
<p><img src="https://gitee.com/xiaomaer-sss/picgo/raw/master/images/2023/1673274431464.png" alt="1673274431464"></p>

      
       <hr><span style="font-style: italic;color: gray;"> 转载请注明来源，欢迎对文章中的引用来源进行考证，欢迎指出任何有错误或不够清晰的表达。可以邮件至 jackma.h@foxmail.com </span>
    </div>
</article>


<p>
    <a  class="dashang" onclick="dashangToggle()">💰</a>
</p>






    




    </div>
    <div class="copyright">
        <p class="footer-entry">
    ©2017 kiwi
</p>
<p class="footer-entry">Built with <a href="https://hexo.io/" target="_blank">Hexo</a> and <a href="https://github.com/yelog/hexo-theme-3-hexo" target="_blank">3-hexo</a> theme</p>

    </div>
    <div class="full-toc">
        <button class="full" data-title="切换全屏 快捷键 s"><span class="min "></span></button>
<a class="" id="rocket" ></a>

    </div>
</div>

<div class="hide_box" onclick="dashangToggle()"></div>
<div class="shang_box">
    <a class="shang_close"  onclick="dashangToggle()">×</a>
    <div class="shang_tit">
        <p>Help us with donation</p>
    </div>
    <div class="shang_payimg">
        <div class="pay_img">
            <img src="/img/alipay.jpg" class="alipay" title="扫码支持">
            <img src="/img/weixin.jpg" class="weixin" title="扫码支持">
        </div>
    </div>
    <div class="shang_payselect">
        <span><label><input type="radio" name="pay" checked value="alipay">alipay</label></span><span><label><input type="radio" name="pay" value="weixin">weixin</label></span>
    </div>
</div>


</body>
<script src="/js/jquery.pjax.js?v=1.1.0" ></script>

<script src="/js/script.js?v=1.1.0" ></script>
<script>
    var img_resize = 'default';
    function initArticle() {
        /*渲染对应的表格样式*/
        
            $("#post .pjax table").addClass("green_title");
        

        /*渲染打赏样式*/
        
        $("input[name=pay]").on("click", function () {
            if($("input[name=pay]:checked").val()=="weixin"){
                $(".shang_box .shang_payimg .pay_img").addClass("weixin_img");
            } else {
                $(".shang_box .shang_payimg .pay_img").removeClass("weixin_img");
            }
        })
        

        /*高亮代码块行号*/
        

        /*访问数量*/
        
        $.getScript("//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js");
        

        /*代码高亮，行号对齐*/
        $('.pre-numbering').css('line-height',$('.has-numbering').css('line-height'));

        
        
    }

    /*打赏页面隐藏与展示*/
    
    function dashangToggle() {
        $(".shang_box").fadeToggle();
        $(".hide_box").fadeToggle();
    }
    

</script>

<!--加入行号的高亮代码块样式-->

<!--自定义样式设置-->
<style>
    
    
    .nav {
        width: 542px;
    }
    .nav.fullscreen {
        margin-left: -542px;
    }
    .nav-left {
        width: 120px;
    }
    
    
    @media screen and (max-width: 1468px) {
        .nav {
            width: 492px;
        }
        .nav.fullscreen {
            margin-left: -492px;
        }
        .nav-left {
            width: 100px;
        }
    }
    
    
    @media screen and (max-width: 1024px) {
        .nav {
            width: 492px;
            margin-left: -492px
        }
        .nav.fullscreen {
            margin-left: 0;
        }
    }
    
    @media screen and (max-width: 426px) {
        .nav {
            width: 100%;
        }
        .nav-left {
            width: 100%;
        }
    }
    
    
    .nav-right .title-list nav a .post-title, .nav-right .title-list #local-search-result a .post-title {
        color: #383636;
    }
    
    
    .nav-right .title-list nav a .post-date, .nav-right .title-list #local-search-result a .post-date {
        color: #5e5e5f;
    }
    
    
    .nav-right nav a.hover, #local-search-result a.hover{
        background-color: #e2e0e0;
    }
    
    

    /*列表样式*/
    
    #post .pjax article .article-entry>ol, #post .pjax article .article-entry>ul, #post .pjax article>ol, #post .pjax article>ul{
        border: #e2dede solid 1px;
        border-radius: 10px;
        padding: 10px 32px 10px 56px;
    }
    #post .pjax article .article-entry li>ol, #post .pjax article .article-entry li>ul,#post .pjax article li>ol, #post .pjax article li>ul{
        padding-top: 5px;
        padding-bottom: 5px;
    }
    #post .pjax article .article-entry>ol>li, #post .pjax article .article-entry>ul>li,#post .pjax article>ol>li, #post .pjax article>ul>li{
        margin-bottom: auto;
        margin-left: auto;
    }
    #post .pjax article .article-entry li>ol>li, #post .pjax article .article-entry li>ul>li,#post .pjax article li>ol>li, #post .pjax article li>ul>li{
        margin-bottom: auto;
        margin-left: auto;
    }
    

    /* 背景图样式 */
    
    #post {
        background: url([object Object]);
    }
    
    
    #post .index {
        background: url([object Object]);
    }
    


    /*引用块样式*/
    

    /*文章列表背景图*/
    
    .nav-right:before {
        content: ' ';
        display: block;
        position: absolute;
        left: 0;
        top: 0;
        width: 100%;
        height: 100%;
        opacity: 0.3;
        background: url("https://i.loli.net/2019/07/22/5d3521411f3f169375.png");
        background-repeat: no-repeat;
        background-position: 50% 0;
        -ms-background-size: cover;
        -o-background-size: cover;
        -moz-background-size: cover;
        -webkit-background-size: cover;
        background-size: cover;
    }
    

    
</style>







</html>
